#include <QDebug>

#include <QDomDocument>
#include <QDesktopWidget>
#include <QDir>
#include <QFile>
#include <QInputDialog>
#include <QMenu>
#include <QProcess>
#include <QSettings>
#include <QX11Info>

#include "ui_dexpanel.h"
#include "dexpanel.h"
#include "dexpanelbtn.h"

/** \todo
 *
 *	Implement _NET_WM_STRUT_PARTIAL
 *
 *	Implement menu system.
 *
 *	Implement window icons.
 *
 *	Implement system tray and other panel applets.
 *
 *	Implement theme system.
 */
DexPanel::DexPanel(QWidget * parent, Qt::WindowFlags f)
	: QMainWindow(parent, f), ui(new Ui::DexPanel)
	{
		setWindowFlags(Qt::FramelessWindowHint /* Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint */ | f);
		setAttribute(Qt::WA_X11NetWmWindowTypeDock, true);
		ui->setupUi(this);
		setGeometry(0,
					QApplication::desktop()->height()-height(),
					QApplication::desktop()->width(),
					height());
		ui->centralWidget->setMaximumSize(QApplication::desktop()->width(),
										  QApplication::desktop()->height());
		constructMenus();

		d_NET_WM_STRUT = XInternAtom(QX11Info::display(), "_NET_WM_STRUT", false);
		d_NET_WM_STRUT_PARTIAL = XInternAtom(QX11Info::display(), "_NET_WM_STRUT_PARTIAL", false);
//		setAttribute(Qt::WA_TranslucentBackground);
//		setWindowOpacity(75);
	}

DexPanel::~DexPanel()
	{
		XDeleteProperty(QX11Info::display(), winId(), d_NET_WM_STRUT);
		delete ui;
	}

QString DexPanel::getWindowName(Window w) const
	{
		char *wName;
		XFetchName(QX11Info::display(), w, &wName);
		QString name(wName);
		XFree(wName);
		if (name.isEmpty() || name == "")
			name = "Untitled";
		return name;
	}

void DexPanel::addClientButton(Window w)
	{
		if (!clientBtns.contains(w) && w != winId())
		{
			QString name = getWindowName(w);
			if (/*name != "Qt-subapplication" &&*/ name != "kwin")
			{
//				qDebug() << name << w;
				DexPanelBtn *btn = new DexPanelBtn(name, this);
				btn->setCheckable(true);
				btn->setWindow(w);
				ui->horizontalLayout->addWidget(btn);
				clientBtns.insert(w, btn);
				btn->show();
			}
		}
	}

void DexPanel::clearPressedDown()
	{
		if (clientBtns.count() > 0)
		{
			foreach (QPushButton *btn, clientBtns)
				btn->setChecked(false);
		}
	}

void DexPanel::constructMenus()
	{
		QStringList titles;
		QDomDocument xdgmenus;
		QFile xmlDoc("/etc/xdg/menus/applications.menu");
		xmlDoc.open(QIODevice::ReadOnly);
		if (xdgmenus.setContent(xmlDoc.readAll()))
		{
			QDomNodeList list = xdgmenus.elementsByTagName("Menu");
			titles << "Dexios";
			for (int i = 1; i < list.count()-2; i++)
			{
				QString text = list.at(i).childNodes().item(0).toElement().text();
				if (text != "More")
					titles << text;
			}
		}
		xmlDoc.close();

		if (titles.count() < 2) // In case there is no applications.menu file
		{
			titles.clear();
			titles << "Dexios"
				   << "Development"
				   << "Education"
				   << "Games"
				   << "Graphics"
				   << "Internet"
				   << "Multimedia"
				   << "Office"
				   << "System"
				   << "Utilities";
		}

		foreach (QString title, titles)
		{
			QMenu *menu = ui->menuBar->addMenu(title);
//			QMenu *menu = ui->menuBar->addMenu(QIcon(getProgramIcon("applications-"+title.toLower(), "categories")), title);
			connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(execApp(QAction*)));
			connect(menu, SIGNAL(aboutToHide()), this, SLOT(unsetHasMenuVisible()));
			connect(menu, SIGNAL(aboutToShow()), this, SLOT(setHasMenuVisible()));
			menus.insert(title, menu);
		}

		genAppsMenus();
	}

void DexPanel::execApp(QAction *action)
	{
		QString prog(action->data().toString());
		QStringList args = prog.split(" ");
		if (args.contains("%F"))
		{
			QStringList a;
			a << QDir::homePath();
			QProcess::startDetached(args[0], a);
		}
		else
			QProcess::startDetached(args[0]);
	}

void DexPanel::genAppsMenus()
	{
		if (!hasMenuVisible)
		{
			qDebug() << "Generating menus ...";
			QString home;
			home = QDir::homePath();
			foreach (QString title, menus.uniqueKeys())
			{
				QFile file(home+"/.dexios/menus/"+title+".xml");
				if (file.exists())
				{
					QDomDocument xml;
					file.open(QIODevice::ReadOnly);
					if (xml.setContent(file.readAll()))
					{
						QMenu *appMenu = menus.value(title);
						appMenu->clear();

						QDomNodeList list = xml.elementsByTagName("app");
						for (int i = 0; i < list.count(); i++)
						{
							QDomNamedNodeMap nodeMap = list.at(i).attributes();
							QDomNode nodeItem = nodeMap.namedItem("hide");
							if (!nodeItem.isNull())
							{
								if (nodeItem.nodeValue() == "false")
								{
									QString appName = nodeMap.namedItem("name").nodeValue();
									QString iconName = nodeMap.namedItem("icon").nodeValue();
									QString execFileName = nodeMap.namedItem("exec").nodeValue();
									appMenu->addAction(appName)->setData(QVariant(execFileName));
								}
							}
						}
					}
				}

				if (title == "Dexios")
				{
					QMenu *appMenu = menus.value(title);
					QFile kickoffConfig(QDir::homePath()+"/.kde4/share/config/kickoffrc");
					if (!kickoffConfig.exists())
						kickoffConfig.setFileName(QDir::homePath()+"/.kde/share/config/kickoffrc");

					if (kickoffConfig.exists())
					{
						QFileInfo fileInfo(kickoffConfig);
						QSettings kickoffRC(fileInfo.absoluteFilePath(), QSettings::IniFormat, this);
						QStringList favorites(kickoffRC.value("Favorites/FavoriteURLs").toStringList());
						foreach (QString desktopFilePath, favorites)
						{
							QSettings desktopFile(desktopFilePath, QSettings::IniFormat, this);
							if (desktopFile.contains("Desktop Entry/Name"))
								appMenu->addAction(QIcon(getProgramIcon(desktopFile.value("Desktop Entry/Icon").toString())),
												   desktopFile.value("Desktop Entry/Name").toString())->setData(desktopFile.value("Desktop Entry/Exec"));
						}
					}
					appMenu->addSeparator();
					appMenu->addAction(tr("&Run ..."), this, SLOT(runDialog()));
					appMenu->addSeparator();
					appMenu->addAction(tr("Log &Out"), this, SLOT(logout()));
				}
			}
		}
	}

QString DexPanel::getProgramIcon(QString iconName, QString dir) const
	{
//		qDebug() << iconName;
		QFile icon(iconName);
		// Check to see if iconName is a file path...
		if (icon.exists())
			return icon.fileName();

		// If not, then search else where...
		if (iconName.contains(".png"))
			icon.setFileName("/usr/share/icons/oxygen/16x16/"+dir+"/"+iconName);
		else
			icon.setFileName("/usr/share/icons/oxygen/16x16/"+dir+"/"+iconName+".png");

		if (icon.exists())
			return icon.fileName();

		// Resort to hicolor...
		if (iconName.contains(".png"))
			icon.setFileName("/usr/share/icons/hicolor/16x16/"+dir+"/"+iconName);
		else
			icon.setFileName("/usr/share/icons/hicolor/16x16/"+dir+"/"+iconName+".png");

		if (icon.exists())
			return icon.fileName();

		// Resort to the second hicolor location...
		if (iconName.contains(".png"))
			icon.setFileName("/usr/local/share/icons/hicolor/16x16/"+dir+"/"+iconName);
		else
			icon.setFileName("/usr/local/share/icons/hicolor/16x16/"+dir+"/"+iconName+".png");

		if (icon.exists())
			return icon.fileName();

		// Resort to Pixmaps...
		if (iconName.contains(".png"))
			icon.setFileName("/usr/share/pixmaps/"+iconName);
		else
			icon.setFileName("/usr/share/pixmaps/"+iconName+".png");

		if (icon.exists())
			return icon.fileName();

		// Sigh... Not going to bother looking else where...
		icon.setFileName("/usr/share/icons/oxygen/16x16/apps/unknownapp.png");
		return icon.fileName();
	}

void DexPanel::logout(){}

void DexPanel::removeClientButton(Window w)
	{
		if (clientBtns.contains(w))
			clientBtns.take(w)->deleteLater();
	}

void DexPanel::runDialog()
	{
		QString proc = QInputDialog::getText(this, tr("Run Program"), tr("Type in program name:"));
		if (!proc.isEmpty())
			QProcess::startDetached(proc);
	}

void DexPanel::setButtonPressed(Window w, bool x)
	{
//		if (!clientBtns.contains(w))
//			addClientButton(w);
		if (clientBtns.contains(w))
			clientBtns.value(w)->setChecked(x);
	}

void DexPanel::setPosition(Position pos)
	{
		quint64 strut[] = {0,0,0,0};
		strut[pos] = (pos < 2) ? width() : height();
		XChangeProperty(QX11Info::display(),
						winId(),
						d_NET_WM_STRUT,
						XA_CARDINAL,
						32,
						PropModeReplace,
						(unsigned char *) strut,
						4);
	}

void DexPanel::updateBtnText(Window w)
	{
		if (clientBtns.contains(w))
		{
			QString name = getWindowName(w);
			clientBtns.value(w)->setText(name);
		}
	}
